/**
 * 
 */
package com.bieber.smartpost.controller;

import com.bieber.smartpost.env.EnvironmentFacade;
import com.bieber.smartpost.invoke.*;
import com.bieber.smartpost.model.RequestEntity;
import com.bieber.smartpost.util.SafeFile;
import com.bieber.smartpost.util.Utils;
import com.jbeer.framework.annotation.Action;
import com.jbeer.framework.annotation.Controller;
import com.jbeer.framework.annotation.RequestParameter;
import com.jbeer.framework.enumeration.RequestType;
import com.jbeer.framework.exception.JBeerException;
import com.jbeer.framework.parser.json.JSON;
import com.jbeer.framework.properties.PropertiesContext;
import com.jbeer.framework.utils.StringUtils;
import com.jbeer.framework.web.ModelAndView;
import com.jbeer.framework.web.ModelAndView.JSONModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.HttpCookie;
import java.net.URL;
import java.util.List;

/**
 * @author bieber
 *
 */
@Controller
public class ProcessorController {


	private static final String SAVE_ACTION="save";
	
	private static final String TYPE_ENTITY="entity";
	
	private static final String TYPE_SCENE="scene";
	
	private static final String TYPE_GROUP="group";

    private static final String TYPE_ENV="env";
	
	private static final String FILE_PATH_PREFIX="data/";
	
	private static final String ENTITY_FILE_NAME="entities.json";
	
	private static final String SCENE_FILE_NAME="scene.json";
	
	private static final String GROUP_FILE_NAME="group.json";

    private static final String ENV_FILE_NAME="env.json";
    
    private static final String SMART_POST_FILE_LAST_UPDATETIME_TOKEN="SMART_POST_FILE_LAST_UPDATETIME_TOKEN";
	
    private static final SafeFile ENTITY_FILE ;

    private static final SafeFile SCENE_FILE;

    private static final SafeFile GROUP_FILE;

    public static final SafeFile ENV_FILE;

    private static final String DATA_FILE_ROOT="data_file_root";

    static{
        String fileRoot = System.getProperty(DATA_FILE_ROOT)==null?System.getenv(DATA_FILE_ROOT):System.getProperty(DATA_FILE_ROOT);
        if(StringUtils.isEmpty(fileRoot)){
            URL classPath = Thread.currentThread().getContextClassLoader().getResource("/")==null?Thread.currentThread().getContextClassLoader().getResource(""):Thread.currentThread().getContextClassLoader().getResource("/");
            fileRoot=classPath.getPath();
        }
        ENTITY_FILE = new SafeFile(fileRoot+File.separator+FILE_PATH_PREFIX+ENTITY_FILE_NAME);
        SCENE_FILE = new SafeFile(fileRoot+File.separator+FILE_PATH_PREFIX+SCENE_FILE_NAME);
        GROUP_FILE = new SafeFile(fileRoot+File.separator+FILE_PATH_PREFIX+GROUP_FILE_NAME);
        ENV_FILE = new SafeFile(fileRoot+File.separator+FILE_PATH_PREFIX+ENV_FILE_NAME);
        try {
            EnvironmentFacade.refreshEnv(ENV_FILE.read());
        } catch (JBeerException e) {
            Utils.COMMONS_LOGGER.debug("failed to inited",e);
        } catch (IOException e) {
            Utils.COMMONS_LOGGER.debug("failed to inited", e);
        }
    }

	@Action(requestType=RequestType.POST,urlPatterns="processor.htm")
	public ModelAndView processor(@RequestParameter("action")String action,@RequestParameter("type")String type,@RequestParameter(value="data",required=false)String data,HttpServletRequest request,HttpServletResponse response) {
			JSONModelAndView jmav = ModelAndView.createJsonModel();
			if(SAVE_ACTION.equalsIgnoreCase(action)){
                try{
				boolean ret = saveData(type,data,request);
				if(ret){
					jmav.setDataMap("status",true);
				}else{
					jmav.setDataMap("status", false);
				}
                }catch (IOException e){
                    Utils.COMMONS_LOGGER.debug("failed to save file ,type:"+type,e);
                    jmav.setDataMap("status",false);
                    jmav.setDataMap("error",e.getMessage());
                } catch (JBeerException e) {
                    Utils.COMMONS_LOGGER.debug("failed to save file ,type:"+type,e);
                    jmav.setDataMap("status",false);
                    jmav.setDataMap("error", e.getMessage());
                }
            }else{
                try{
                    String content = readData(type,response);
                    jmav.setData(content);
                }catch(Exception e){
                    Utils.COMMONS_LOGGER.debug("failed to read data,type:"+type,e);
                }
			}
			return jmav;
	}
	private boolean saveData(String type,String data,HttpServletRequest request) throws IOException, JBeerException {
        SafeFile file = getFile(type);
        if(type.equals("env")){
            EnvironmentFacade.refreshEnv(data);
        }
        if(checkFileOutTime(type,file.getLastUpdateTime(),request)) {
            file.write(data);
            return true;
        }
        return false;
	}
    

    private boolean checkFileOutTime(String type,long lastUpdateTime,HttpServletRequest request) throws IOException {
        Cookie[] cookies = request.getCookies();
        long clientLastUpdateTime =-1;
        for(Cookie cookie:cookies){
            if(cookie.getName().equals(SMART_POST_FILE_LAST_UPDATETIME_TOKEN+type)){
                String value=cookie.getValue();
                if(value!=null&&value.trim().length()>0){
                    clientLastUpdateTime= Long.parseLong(value);
                }
                break;
            }
        }
        if(clientLastUpdateTime!=lastUpdateTime){
            Utils.COMMONS_LOGGER.debug("file had update,client last update time is "+clientLastUpdateTime+",server last update time is "+lastUpdateTime);
            throw new IOException("您当前持有的文件已经超时，被其他人进行了修改<br/>已经自动获取最新数据，请重试！");
        }
        return true;
    }
	private String readData(String type,HttpServletResponse response) throws IOException {
		    SafeFile file = getFile(type);
            Cookie cookie = new Cookie(SMART_POST_FILE_LAST_UPDATETIME_TOKEN+type,file.getLastUpdateTime()+"");
            response.addCookie(cookie);
			if(file==null){
                return null;
            }else{
                return file.read();
            }
	}
    
    private SafeFile  getFile(String type){
        if(TYPE_ENTITY.equalsIgnoreCase(type)){
            return ENTITY_FILE;
        }else if(TYPE_SCENE.equalsIgnoreCase(type)){
            return SCENE_FILE;
        }else if(TYPE_GROUP.equalsIgnoreCase(type)){
            return GROUP_FILE;
        }else if(TYPE_ENV.equalsIgnoreCase(type)){
            return ENV_FILE;
        }else{
            return null;
        }
    }
    @Action(urlPatterns = "batchInvoke.htm")
    public ModelAndView batchInvoke(@RequestParameter("entityArray")String entityArray,HttpServletResponse response,HttpServletRequest request){
        JSONModelAndView jsonModelAndView = ModelAndView.createJsonModel();
        try {
            List<RequestEntity> entityList = JSON.readList(entityArray, RequestEntity.class);
            String clientIp = request.getRemoteHost();

            for(RequestEntity entity:entityList){
                entity.setClientIp(clientIp);
            }
            HttpInvokeTask task = new HttpInvokeTask(entityList);
            List<HttpCookie> cookies = Utils.getCookies(request);
            if(cookies!=null){
                CookieContainer.cacheCookies(task.getInvokeId(), cookies);
            }
            BatchHttpInvoker.submitTask(task);
            jsonModelAndView.setDataMap("status",true);
            jsonModelAndView.setDataMap("invokeId",task.getInvokeId());
        } catch (JBeerException e) {
            Utils.COMMONS_LOGGER.debug("failed to batch invoke request",e);
            jsonModelAndView.setDataMap("status",false);
            jsonModelAndView.setDataMap("error", e.getMessage());
        }
        return jsonModelAndView;
    }
    @Action(urlPatterns="login.htm")
    public ModelAndView login(@RequestParameter(value="password",required = false)String password,@RequestParameter("isLogined")boolean isLogined,HttpServletResponse response){
        JSONModelAndView jsonModelAndView = ModelAndView.createJsonModel();
        if(isLogined){
            Cookie cookie = new Cookie("isRoot","false");
            response.addCookie(cookie);
            jsonModelAndView.setDataMap("status",true);
            return jsonModelAndView;
        }
        String rootPwd =  PropertiesContext.getProperties("root");
        if(password.equalsIgnoreCase(rootPwd)){
            Cookie cookie = new Cookie("isRoot","true");
            response.addCookie(cookie);
            jsonModelAndView.setDataMap("status",true);
        }else{
            jsonModelAndView.setDataMap("status",false);
        }
        return jsonModelAndView;
    }
    
    @Action(urlPatterns="queryInvokeResult.htm")
    public ModelAndView queryInvokeResult(@RequestParameter("invokeId")String invokeId,HttpServletResponse response){
        JSONModelAndView jsonModelAndView = ModelAndView.createJsonModel();
        HttpInvokerResult result = BatchHttpInvokeResultQueue.getResult(invokeId);
        if(result==null){
            jsonModelAndView.setDataMap("status",false);
        }else{
            jsonModelAndView.setDataMap("status",true);
            if(result.getResponseContent()==null){
                result.setResponseContent("No response");
            }
            jsonModelAndView.setDataMap("data",result.getInvokeMetadata());
            if(result.getResponseHeader()!=null){
                Utils.setCookies(response,result.getResponseHeader().getCookies());
            }
        }
        return jsonModelAndView;
    }
}
